home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / kernel / write.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  65.2 KB  |  2,494 lines  |  [TEXT/R*ch]

  1. /* Xconq game module writing.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11. extern void init_write PARAMS ((void));
  12. extern char *shortest_escaped_name PARAMS ((int u));
  13. extern int xmalloc_warnings;
  14. extern int memory_exhausted;
  15. extern Feature *featurelist;
  16. extern Doctrine *doctrine_list;
  17. #include "imf.h"
  18. extern ImageFamily **recorded_imfs;
  19. extern int num_recorded_imfs;
  20.  
  21. #define key(x) (keyword_name(x))
  22.  
  23. static void start_form PARAMS ((char *hd));
  24. static void add_to_form PARAMS ((char *x));
  25. static void add_num_to_form PARAMS ((int x));
  26. static void add_num_or_dice_to_form PARAMS ((int x));
  27. static void end_form PARAMS ((void));
  28. static void newline_form PARAMS ((void));
  29. static void space_form PARAMS ((void));
  30. static char *escaped_symbol PARAMS ((char *str));
  31. static char *escaped_string PARAMS ((char *str));
  32. static void write_bool_prop PARAMS ((char *name, int value,
  33.                      int dflt, int nodefaulting,
  34.                      int addnewline));
  35. static void write_num_prop PARAMS ((char *name, int value,
  36.                     int dflt, int nodefaulting,
  37.                     int addnewline));
  38. static void write_str_prop PARAMS ((char *name, char *value,
  39.                     char *dflt, int nodefaulting,
  40.                     int addnewline));
  41. static int string_not_default PARAMS ((char *str, char *dflt));
  42. static void write_lisp_prop PARAMS ((char *name, struct a_obj *value,
  43.                      struct a_obj *dflt, int nodefaulting,
  44.                      int as_cdr, int addnewline));
  45. static void write_utype_value_list PARAMS ((char *name, short *arr,
  46.                         int dflt, int addnewline));
  47. static void write_mtype_value_list PARAMS ((char *name, short *arr,
  48.                         int dflt, int addnewline));
  49. static void write_side_value_list PARAMS ((char *name, short *arr,
  50.                        int dflt, int addnewline));
  51. static void write_utype_string_list PARAMS ((char *name, char **arr,
  52.                          char *dflt, int addnewline));
  53. static void write_types PARAMS ((void));
  54. static void write_tables PARAMS ((int compress));
  55. static void write_type_name_list PARAMS ((int typ, int *flags, int dim));
  56. #if 0
  57. static void write_type_value_list PARAMS ((int typ, int *flags, int dim,
  58.                        int (*getter)(int, int), int i));
  59. #endif
  60. static void write_table PARAMS ((char *name, int (*getter)(int, int),
  61.                  int dflt, int typ1, int typ2, int compress));
  62. static void write_world PARAMS ((void));
  63. static void write_areas PARAMS ((Module *module));
  64. static void write_area_terrain PARAMS ((int compress));
  65. static void write_area_aux_terrain PARAMS ((int compress));
  66. static void write_area_features PARAMS ((int compress));
  67. static void write_area_elevations PARAMS ((int compress));
  68. static void write_area_people_sides PARAMS ((int compress));
  69. static void write_area_materials PARAMS ((int compress));
  70. static void write_area_temperatures PARAMS ((int compress));
  71. static void write_area_clouds PARAMS ((int compress));
  72. static void write_area_winds PARAMS ((int compress));
  73. static void write_globals PARAMS ((void));
  74. static void write_scorekeepers PARAMS ((void));
  75. static void write_doctrines PARAMS ((void));
  76. static void write_sides PARAMS ((Module *module));
  77. static void write_side_properties PARAMS ((Side *side));
  78. static int fn_terrain_view PARAMS ((int x, int y));
  79. static int fn_aux_terrain_view PARAMS ((int x, int y));
  80. static int fn_aux_terrain_view_date PARAMS ((int x, int y));
  81. static int fn_terrain_view_date PARAMS ((int x, int y));
  82. static int fn_unit_view PARAMS ((int x, int y));
  83. static int fn_unit_view_date PARAMS ((int x, int y));
  84. static int fn_temp_view PARAMS ((int x, int y));
  85. static int fn_temp_view_date PARAMS ((int x, int y));
  86. static int fn_cloud_view PARAMS ((int x, int y));
  87. static int fn_cloud_bottom_view PARAMS ((int x, int y));
  88. static int fn_cloud_height_view PARAMS ((int x, int y));
  89. static int fn_cloud_view_date PARAMS ((int x, int y));
  90. static int fn_wind_view PARAMS ((int x, int y));
  91. static int fn_wind_view_date PARAMS ((int x, int y));
  92. static void write_side_view PARAMS ((Side *side, int compress));
  93. static void write_one_side_view_layer PARAMS ((int propkey, int (*fn)(int x, int y)));
  94. static void write_players PARAMS ((void));
  95. static void write_player PARAMS ((struct a_player *player));
  96. static void write_agreements PARAMS ((void));
  97. static void write_agreement PARAMS ((struct a_agreement *agreement));
  98. static void write_units PARAMS ((Module *module));
  99. static void write_unit_properties PARAMS ((Unit *unit));
  100. static void write_unit_act PARAMS ((Unit *unit));
  101. static void write_unit_plan PARAMS ((Unit *unit));
  102. static void write_task PARAMS ((Task *task));
  103. static void write_goal PARAMS ((Goal *goal, int keyword));
  104. static void write_rle PARAMS ((int (*datafn)(int, int), int lo, int hi,
  105.                    int (*translator)(int), int compress));
  106. static void write_run PARAMS ((int run, int val));
  107. static void write_history PARAMS ((void));
  108. static void write_past_unit PARAMS ((PastUnit *pastunit));
  109. static void write_historical_event PARAMS ((HistEvent *hevt));
  110. static void write_images PARAMS ((void));
  111. static int reshaped_point PARAMS ((int x1, int y1, int *x2p, int *y2p));
  112. static int original_point PARAMS ((int x1, int y1, int *x2p, int *y2p));
  113.  
  114. /* The pointer to the file being written to. */
  115.  
  116. static FILE *fp;
  117.  
  118. /* True if the area is to be saved to a different size than it is now. */
  119.  
  120. static int doreshape;
  121.  
  122. static Module *reshaper;
  123.  
  124. /* A pre-allocated module used for when we're saving the game and may
  125.    not do any more allocation. */
  126.  
  127. static Module *spare_module;
  128.  
  129. static char *shortestbuf;
  130.  
  131. static char *escapedthingbuf;
  132.  
  133. static int tmpcompress;
  134.  
  135. /* Preparation and preallocation for writing. */
  136.  
  137. void
  138. init_write()
  139. {
  140.     spare_module = create_game_module("spare module");
  141.     shortestbuf = xmalloc(BUFSIZE);
  142.     escapedthingbuf = xmalloc(BUFSIZE);
  143. }
  144.  
  145. /* Little routines to do low-level syntax.  While these look excessive, calling fprintf
  146.    directly would result in an object code size increase of as much as 25%. */
  147.  
  148. static void
  149. start_form(hd)
  150. char *hd;
  151. {
  152.     fprintf(fp, "(%s", hd);
  153. }
  154.  
  155. static void
  156. add_to_form(x)
  157. char *x;
  158. {
  159.     fprintf(fp, " %s", x);
  160. }
  161.  
  162. static void
  163. add_num_to_form(x)
  164. int x;
  165. {
  166.     fprintf(fp, " %d", x);
  167. }
  168.  
  169. /* Write either a normal value or a dice spec, as appropriate. */
  170.  
  171. static void
  172. add_num_or_dice_to_form(x)
  173. int x;
  174. {
  175.     if (x >> 14 == 1) {
  176.     fprintf(fp, " %dd%d+%d", (x >> 11) & 0x07, (x >> 7) & 0x0f, x & 0x7f);
  177.     } else {
  178.     fprintf(fp, " %d", x);
  179.     }
  180. }
  181.  
  182. static void
  183. end_form()
  184. {
  185.     fprintf(fp, ")");
  186. }
  187.  
  188. static void
  189. newline_form()
  190. {
  191.     fprintf(fp, "\n");
  192. }
  193.  
  194. static void
  195. space_form()
  196. {
  197.     fprintf(fp, " ");
  198. }
  199.  
  200. /* These two routines make sure that any symbols and strings can
  201.    be read in again. */
  202.  
  203. static char *
  204. escaped_symbol(str)
  205. char *str;
  206. {
  207.     char *tmp = str;
  208.  
  209.     if (str[0] == '|' && str[strlen(str)-1] == '|')
  210.       return str;
  211.     while (*tmp != '\0') {
  212.     if (((char *) strchr(" ()#\";|", *tmp)) != NULL || isdigit(str[0])) {
  213.         sprintf(escapedthingbuf, "|%s|", str);
  214.         return escapedthingbuf;
  215.     }
  216.     ++tmp;
  217.     }
  218.     return str;
  219. }
  220.  
  221. /* Note that this works correctly on NULL strings, turning them into
  222.    strings of length 0. */
  223.  
  224. static char *
  225. escaped_string(str)
  226. char *str;
  227. {
  228.     char *tmp = str, *rslt = escapedthingbuf;
  229.  
  230.     *rslt++ = '"';
  231.     if (str != NULL) {
  232.     while (*tmp != 0) {
  233.         if (*tmp == '"') *rslt++ = '\\';
  234.         *rslt++ = *tmp++;
  235.     }
  236.     }
  237.     *rslt++ = '"';
  238.     *rslt = '\0';
  239.     return escapedthingbuf;
  240. }
  241.  
  242. static void
  243. write_bool_prop(name, value, dflt, nodefaulting, addnewline)
  244. char *name;
  245. int value, dflt, nodefaulting, addnewline;
  246. {
  247.     if (nodefaulting || value != dflt) {
  248.     space_form();
  249.     start_form(name);
  250.     add_to_form((value ? "true" : "false"));
  251.     end_form();
  252.     if (addnewline) {
  253.         newline_form();
  254.         space_form();
  255.     }
  256.     }
  257. }
  258.  
  259. static void
  260. write_num_prop(name, value, dflt, nodefaulting, addnewline)
  261. char *name;
  262. int value, dflt, nodefaulting, addnewline;
  263. {
  264.     if (nodefaulting || value != dflt) {
  265.     space_form();
  266.     start_form(name);
  267.     /* (should check that this is always correct to use here) */
  268.     add_num_or_dice_to_form(value);
  269.     end_form();
  270.     if (addnewline) {
  271.         newline_form();
  272.         space_form();
  273.     }
  274.     }
  275. }
  276.  
  277. /* Handle the writing of a single string-valued property. */
  278.  
  279. static void
  280. write_str_prop(name, value, dflt, nodefaulting, addnewline)
  281. char *name, *value, *dflt;
  282. int nodefaulting, addnewline;
  283. {
  284.     if (nodefaulting || string_not_default(value, dflt)) {
  285.     space_form();
  286.     start_form(name);
  287.     add_to_form(escaped_string(value));
  288.     end_form();
  289.     if (addnewline) {
  290.         newline_form();
  291.         space_form();
  292.     }
  293.     }
  294. }
  295.  
  296. static int
  297. string_not_default(str, dflt)
  298. char *str, *dflt;
  299. {
  300.     if (empty_string(dflt)) {
  301.     if (empty_string(str)) {
  302.         return FALSE;
  303.     } else {
  304.         return TRUE;
  305.     }
  306.     } else {
  307.     if (empty_string(str)) {
  308.         return TRUE;
  309.     } else {
  310.         return (strcmp(str, dflt) != 0);
  311.     }
  312.     }
  313. }
  314.  
  315. static void
  316. write_lisp_prop(name, value, dflt, nodefaulting, as_cdr, addnewline)
  317. char *name;
  318. Obj *value, *dflt;
  319. int nodefaulting, as_cdr, addnewline;
  320. {
  321.     Obj *rest;
  322.  
  323.     /* Sanity check. */
  324.     if (value == NULL) {
  325.     run_warning("Property \"%s\" has a bad value NULL, ignoring", name);
  326.     return;
  327.     }
  328.     if (nodefaulting || !equal(value, dflt)) {
  329.     space_form();
  330.     start_form(name);
  331.     if (as_cdr && consp(value)) {
  332.         for_all_list(value, rest) {
  333.             space_form();
  334.             fprintlisp(fp, car(rest));
  335.         }
  336.     } else {
  337.         space_form();
  338.         fprintlisp(fp, value);
  339.     }
  340.     end_form();
  341.     if (addnewline) {
  342.         newline_form();
  343.         space_form();
  344.     }
  345.     }
  346. }
  347.  
  348. static void
  349. write_utype_value_list(name, arr, dflt, addnewline)
  350. char *name;
  351. short *arr;
  352. int dflt, addnewline;
  353. {
  354.     int u, writeany;
  355.  
  356.     if (arr == NULL)
  357.       return;
  358.     writeany = FALSE;
  359.     for_all_unit_types(u) {
  360.     if (arr[u] != dflt) {
  361.         writeany = TRUE;
  362.         break;
  363.     }
  364.     }
  365.     if (!writeany)
  366.       return;
  367.     space_form();
  368.     start_form(name);
  369.     for_all_unit_types(u) {
  370.     add_num_to_form(arr[u]);
  371.     }
  372.     end_form();
  373.     if (addnewline) {
  374.     newline_form();
  375.     space_form();
  376.     }
  377. }
  378.  
  379. static void
  380. write_mtype_value_list(name, arr, dflt, addnewline)
  381. char *name;
  382. short *arr;
  383. int dflt, addnewline;
  384. {
  385.     int m, writeany;
  386.  
  387.     if (nummtypes == 0 || arr == NULL)
  388.       return;
  389.     writeany = FALSE;
  390.     for_all_material_types(m) {
  391.     if (arr[m] != dflt) {
  392.         writeany = TRUE;
  393.         break;
  394.     }
  395.     }
  396.     if (!writeany)
  397.       return;
  398.     space_form();
  399.     start_form(name);
  400.     for_all_material_types(m) {
  401.     add_num_to_form(arr[m]);
  402.     }
  403.     end_form();
  404.     if (addnewline) {
  405.     newline_form();
  406.     space_form();
  407.     }
  408. }
  409.  
  410. static void
  411. write_side_value_list(name, arr, dflt, addnewline)
  412. char *name;
  413. short *arr;
  414. int dflt, addnewline;
  415. {
  416.     int s, writeany;
  417.  
  418.     if (arr == NULL)
  419.       return;
  420.     writeany = FALSE;
  421.     for (s = 0; s <= numsides; ++s) {
  422.     if (arr[s] != dflt) {
  423.         writeany = TRUE;
  424.         break;
  425.     }
  426.     }
  427.     if (!writeany)
  428.       return;
  429.     space_form();
  430.     start_form(name);
  431.     for (s = 0; s <= numsides; ++s) {
  432.     add_num_to_form(arr[s]);
  433.     }
  434.     end_form();
  435.     if (addnewline) {
  436.     newline_form();
  437.     space_form();
  438.     }
  439. }
  440.  
  441. static void
  442. write_utype_string_list(name, arr, dflt, addnewline)
  443. char *name;
  444. char **arr, *dflt;
  445. int addnewline;
  446. {
  447.     int u, writeany;
  448.  
  449.     if (arr == NULL)
  450.       return;
  451.     writeany = FALSE;
  452.     for_all_unit_types(u) {
  453.     if (arr[u] != dflt /* bogus, should use strcmp */) {
  454.         writeany = TRUE;
  455.         break;
  456.     }
  457.     }
  458.     if (!writeany)
  459.       return;
  460.     space_form();
  461.     start_form(name);
  462.     for_all_unit_types(u) {
  463.     add_to_form(escaped_string(arr[u]));
  464.     }
  465.     end_form();
  466.     if (addnewline) {
  467.     newline_form();
  468.     space_form();
  469.     }
  470. }
  471.  
  472. /* Return the shortest properly escaped name that can be used to identify
  473.    unit type. */
  474.  
  475. char *
  476. shortest_escaped_name(u)
  477. int u;
  478. {
  479.     char *typename = u_type_name(u);
  480.  
  481.     if (strlen(u_internal_name(u)) < strlen(typename)) {
  482.     typename = u_internal_name(u);
  483.     }
  484.     sprintf(shortestbuf, "%s", escaped_symbol(typename));
  485.     return shortestbuf;
  486. }
  487.  
  488. /* A saved game should include everything necessary to recreate a game
  489.    exactly.  It is important that this routine not attempt to use graphics,
  490.    since it may be called when graphics code fails, and that it not allocate
  491.    memory, since it may be called upon memory exhaustion.  Returns TRUE if
  492.    that save was successful. */
  493.  
  494. int
  495. write_entire_game_state(fname)
  496. char *fname;
  497. {
  498.     Module *module;
  499.     int rslt;
  500.  
  501.     /* Note in the history that a copy was made. */
  502.     if (!memory_exhausted)
  503.       record_event(H_GAME_SAVED, ALLSIDES);
  504.     /* No additional allocation should ever happen during saving,
  505.        so complain if it does. */
  506.     xmalloc_warnings = TRUE;
  507.     module = spare_module;
  508.     /* Reset the module's contents, might have been used already. */
  509.     memset(module, 0, sizeof(Module));
  510.     module->name = fname;
  511.     module->filename = fname;
  512.     module->instructions = lispnil;
  513.     module->notes = lispnil;
  514.     module->designnotes = lispnil;
  515.     module->startlineno = 1;
  516.     module->endlineno = 1;
  517.     module->compress_tables = TRUE;
  518.     module->compress_layers = TRUE;
  519.     module->def_all = TRUE;
  520.     /* Record information about the original main module, for use after
  521.        the game has been restored.  mainmodule should point to something,
  522.        but it doesn't actually have to. */
  523.     if (mainmodule != NULL) {
  524.     module->origmodulename = mainmodule->name;
  525.     module->origvariants = mainmodule->variants;
  526.     module->origversion = mainmodule->version;
  527.     }
  528.     rslt = write_game_module(module);
  529.     xmalloc_warnings = FALSE;
  530.     /* Record that the game's state is accurately saved away. */
  531.     if (rslt)
  532.       gamestatesafe = TRUE;
  533.     return rslt;
  534. }
  535.  
  536. /* Given a game module telling what is in the module, write out a file
  537.    containing the requested content.  Return true if everything went OK. */
  538.  
  539. int
  540. write_game_module(module)
  541. Module *module;
  542. {
  543.     int i;
  544.     Obj *rest;
  545.     Variant *var;
  546.     Module *origmodule;
  547.  
  548.     if (module->filename == NULL) {
  549.     /* (should be an error?) */
  550.     return FALSE;
  551.     }
  552.     fp = fopen(module->filename, "w");
  553.     if (fp != NULL) {
  554.     /* Write the definition of this game module. */
  555.     start_form(key(K_GAME_MODULE));
  556.     add_to_form(escaped_string(module->name));
  557.     newline_form();
  558.     space_form();
  559.     if (module->def_all) {
  560.         write_str_prop(key(K_TITLE), module->title,
  561.                "", FALSE, TRUE);
  562.         write_str_prop(key(K_BLURB), module->blurb,
  563.                "", FALSE, TRUE);
  564.         write_str_prop(key(K_PICTURE_NAME), module->picturename,
  565.                "", FALSE, TRUE);
  566.         write_str_prop(key(K_BASE_MODULE), module->basemodulename,
  567.                "", FALSE, TRUE);
  568.         write_str_prop(key(K_DEFAULT_BASE_MODULE), module->defaultbasemodulename,
  569.                "", FALSE, TRUE);
  570.         write_str_prop(key(K_BASE_GAME), module->basegame,
  571.                "", FALSE, TRUE);
  572.         write_str_prop(key(K_VERSION), module->version,
  573.                "", FALSE, TRUE);
  574.         write_str_prop(key(K_PROGRAM_VERSION), version_string(),
  575.                "", FALSE, TRUE);
  576.         if (module->variants) {
  577.         start_form(key(K_VARIANTS));
  578.         for (i = 0; module->variants[i].id != lispnil; ++i) {
  579.             var = &(module->variants[i]);
  580.             if (!empty_string(var->name)) {
  581.             start_form(escaped_string(var->name));
  582.             if (symbolp(var->id)) {
  583.                 add_to_form(c_string(var->id));
  584.             } else {
  585.                 space_form();
  586.                 fprintlisp(fp, var->id);
  587.             }
  588.             } else if (symbolp(var->id)) {
  589.             start_form(c_string(var->id));
  590.             } else {
  591.             start_form("");
  592.             fprintlisp(fp, var->id);
  593.             }
  594.             if (var->dflt != lispnil) {
  595.             space_form();
  596.             fprintlisp(fp, var->dflt);
  597.             }
  598.             for_all_list(var->cases, rest) {
  599.             space_form();
  600.             fprintlisp(fp, car(rest));
  601.             }
  602.             end_form();
  603.         }
  604.         end_form();
  605.         newline_form();
  606.         }
  607.         /* Write out the "original variants" selected for a game.  Note that
  608.            since these are just used to record into scorefiles, we need only
  609.            the values, not full variant definitions. */
  610.         write_str_prop(key(K_ORIGINAL_MODULE), module->origmodulename,
  611.                "", FALSE, TRUE);
  612.         if (module->origvariants) {
  613.         space_form();
  614.         start_form(key(K_ORIGINAL_VARIANTS));
  615.         for (i = 0; module->origvariants[i].id != lispnil; ++i) {
  616.             var = &(module->origvariants[i]);
  617.             space_form();
  618.             if (symbolp(var->id)) {
  619.             start_form(c_string(var->id));
  620.             } else {
  621.             start_form("");
  622.             add_num_to_form(i);
  623.             }
  624.             if (var->hasintvalue) {
  625.             add_num_to_form(var->intvalue);
  626.             }
  627.             end_form();
  628.         }
  629.         end_form();
  630.         newline_form();
  631.         space_form();
  632.         }
  633.     }
  634.     space_form();
  635.     end_form();
  636.     newline_form();
  637.     newline_form();
  638.     if (module->def_all || module->def_types)
  639.       write_types();
  640.     if (module->def_all || module->def_tables)
  641.       write_tables(module->compress_tables);
  642.     if (module->def_all || module->def_globals)
  643.       write_globals();
  644.     if (1 /* need to suppress synthesis after reload */) {
  645.       start_form(key(K_SET));
  646.       add_to_form("synthesis-methods");
  647.       add_to_form("nil");
  648.       end_form();
  649.       newline_form();
  650.     }
  651.     if (module->def_all || module->def_scoring)
  652.       write_scorekeepers();
  653.     doreshape = reshape_the_output(module);
  654.     reshaper = module;
  655.     if (module->def_all || module->def_world)
  656.       write_world();
  657.     if (module->def_all || module->def_areas)
  658.       write_areas(module);
  659.     if (module->def_all || module->def_sides)
  660.       write_doctrines();
  661.     if (module->def_all || module->def_sides)
  662.       write_sides(module);
  663.     if (module->def_all || module->def_players)
  664.       write_players();
  665.     if (module->def_all || module->def_agreements)
  666.       write_agreements();
  667.     if (module->def_all || module->def_units)
  668.       write_units(module);
  669.     if (module->def_all || module->def_history)
  670.       write_history();
  671.     if (module->def_all)
  672.       write_images();
  673.     /* Write the game notes here (seems reasonable, no deeper reason). */
  674.     if (module->instructions != lispnil) {
  675.         start_form(key(K_GAME_MODULE));
  676.         space_form();
  677.         write_lisp_prop(key(K_INSTRUCTIONS), module->instructions,
  678.                 lispnil, FALSE, FALSE, TRUE);
  679.         newline_form();
  680.         space_form();
  681.         space_form();
  682.         end_form();
  683.         newline_form();
  684.         newline_form();
  685.     }
  686.     if (module->notes != lispnil) {
  687.         start_form(key(K_GAME_MODULE));
  688.         space_form();
  689.         write_lisp_prop(key(K_NOTES), module->notes,
  690.                 lispnil, FALSE, FALSE, TRUE);
  691.         newline_form();
  692.         space_form();
  693.         space_form();
  694.         end_form();
  695.         newline_form();
  696.         newline_form();
  697.     }
  698.     if (module->designnotes != lispnil) {
  699.         start_form(key(K_GAME_MODULE));
  700.         space_form();
  701.         write_lisp_prop(key(K_DESIGN_NOTES), module->designnotes,
  702.                 lispnil, FALSE, FALSE, TRUE);
  703.         newline_form();
  704.         space_form();
  705.         space_form();
  706.         end_form();
  707.         newline_form();
  708.         newline_form();
  709.     }
  710.     fclose(fp);
  711.     return TRUE;
  712.     } else {
  713.     return FALSE;
  714.     }
  715. }
  716.  
  717. /* Write definitions of all the types. */
  718.  
  719. static void
  720. write_types()
  721. {
  722.     int u, m, t, i, ival;
  723.     char *typename, *sval;
  724.     Obj *obj;
  725.  
  726.     /* (or write out all the default values first for doc, then
  727.        only write changed values) */
  728.  
  729.     for_all_unit_types(u) {
  730.     start_form(key(K_UNIT_TYPE));
  731.     typename = shortest_escaped_name(u);
  732.     add_to_form(typename);
  733.     newline_form();
  734.     space_form();
  735.     for (i = 0; utypedefns[i].name != NULL; ++i) {
  736.         /* Don't write out props used internally only, unless debugging. */
  737.         if ((strncmp(utypedefns[i].name, "zz-", 3) == 0) && !Debug)
  738.           continue;
  739.         if (utypedefns[i].intgetter) {
  740.         ival = (*(utypedefns[i].intgetter))(u);
  741.         write_num_prop(utypedefns[i].name, ival,
  742.                    utypedefns[i].dflt, FALSE, TRUE);
  743.         } else if (utypedefns[i].strgetter) {
  744.         sval = (*(utypedefns[i].strgetter))(u);
  745.         /* Special-case a couple possibly-redundant slots. */
  746.         if (utypedefns[i].strgetter == u_type_name
  747.             && strcmp(typename, sval) == 0)
  748.           continue;
  749.         if (utypedefns[i].strgetter == u_internal_name
  750.             && strcmp(typename, sval) == 0)
  751.           continue;
  752.         write_str_prop(utypedefns[i].name, sval,
  753.                    utypedefns[i].dfltstr, FALSE, TRUE);
  754.         } else {
  755.         obj = (*(utypedefns[i].objgetter))(u);
  756.         write_lisp_prop(utypedefns[i].name, obj,
  757.                 lispnil, FALSE, FALSE, TRUE);
  758.         }
  759.     }
  760.     space_form();
  761.     end_form();
  762.     newline_form();
  763.     }
  764.     newline_form();
  765.     for_all_material_types(m) {
  766.     start_form(key(K_MATERIAL_TYPE));
  767.     add_to_form(escaped_symbol(m_type_name(m)));
  768.     newline_form();
  769.     space_form();
  770.     for (i = 0; mtypedefns[i].name != NULL; ++i) {
  771.         /* Don't write out props used internally only, unless debugging. */
  772.         if ((strncmp(mtypedefns[i].name, "zz-", 3) == 0) && !Debug)
  773.           continue;
  774.         if (mtypedefns[i].intgetter) {
  775.         ival = (*(mtypedefns[i].intgetter))(m);
  776.         write_num_prop(mtypedefns[i].name, ival,
  777.                    mtypedefns[i].dflt, FALSE, TRUE);
  778.         } else if (mtypedefns[i].strgetter) {
  779.         sval = (*(mtypedefns[i].strgetter))(m);
  780.         /* Special-case a a possibly-redundant slot. */
  781.         if (mtypedefns[i].strgetter == m_type_name
  782.             && strcmp(typename, sval) == 0)
  783.           continue;
  784.         write_str_prop(mtypedefns[i].name, sval,
  785.                    mtypedefns[i].dfltstr, FALSE, TRUE);
  786.         } else {
  787.         obj = (*(mtypedefns[i].objgetter))(m);
  788.         write_lisp_prop(mtypedefns[i].name, obj,
  789.                 lispnil, FALSE, FALSE, TRUE);
  790.         }
  791.     }
  792.     space_form();
  793.     end_form();
  794.     newline_form();
  795.     }
  796.     newline_form();
  797.     for_all_terrain_types(t) {
  798.     start_form(key(K_TERRAIN_TYPE));
  799.     add_to_form(escaped_symbol(t_type_name(t)));
  800.     newline_form();
  801.     space_form();
  802.     for (i = 0; ttypedefns[i].name != NULL; ++i) {
  803.         /* Don't write out props used internally only, unless debugging. */
  804.         if ((strncmp(ttypedefns[i].name, "zz-", 3) == 0) && !Debug)
  805.           continue;
  806.         if (ttypedefns[i].intgetter) {
  807.         ival = (*(ttypedefns[i].intgetter))(t);
  808.         write_num_prop(ttypedefns[i].name, ival,
  809.                    ttypedefns[i].dflt, FALSE, TRUE);
  810.         } else if (ttypedefns[i].strgetter) {
  811.         sval = (*(ttypedefns[i].strgetter))(t);
  812.         /* Special-case a a possibly-redundant slot. */
  813.         if (ttypedefns[i].strgetter == t_type_name
  814.             && strcmp(typename, sval) == 0)
  815.           continue;
  816.         write_str_prop(ttypedefns[i].name, sval,
  817.                    ttypedefns[i].dfltstr, FALSE, TRUE);
  818.         } else {
  819.         obj = (*(ttypedefns[i].objgetter))(t);
  820.         write_lisp_prop(ttypedefns[i].name, obj,
  821.                 lispnil, FALSE, FALSE, TRUE);
  822.         }
  823.     }
  824.     space_form();
  825.     end_form();
  826.     newline_form();
  827.     }
  828.     newline_form();
  829. }
  830.  
  831. /* Write definitions of all the tables. */
  832.  
  833. static void
  834. write_tables(compress)
  835. int compress;
  836. {
  837.     int tbl;
  838.  
  839.     newline_form();
  840.     for (tbl = 0; tabledefns[tbl].name != 0; ++tbl) {
  841.     /* Don't write out tables used internally only, unless debugging. */
  842.     if ((strncmp(tabledefns[tbl].name, "zz-", 3) == 0) && !Debug)
  843.       continue;
  844.     if (*(tabledefns[tbl].table) != NULL) {
  845.         write_table(tabledefns[tbl].name,
  846.             tabledefns[tbl].getter, tabledefns[tbl].dflt,
  847.             tabledefns[tbl].index1, tabledefns[tbl].index2, compress);
  848.         newline_form();
  849.     }
  850.     }
  851. }
  852.  
  853. #define star_from_typ(typ)  \
  854.   ((typ) == UTYP ? "u*" : ((typ) == MTYP ? "m*" :"t*"))
  855.  
  856. #define name_from_typ(typ, i)  \
  857.   ((typ) == UTYP ? shortest_escaped_name(i) : ((typ) == MTYP ? m_type_name(i) : t_type_name(i)))
  858.  
  859. static void
  860. write_type_name_list(typ, flags, dim)
  861. int typ, *flags, dim;
  862. {
  863.     int j, first = TRUE, listlen = 0;
  864.  
  865.     if (flags == NULL)
  866.       return;
  867.     for (j = 0; j < dim; ++j)
  868.       if (flags[j])
  869.         ++listlen;
  870.     if (listlen > 1)
  871.       start_form("");
  872.     for (j = 0; j < dim; ++j) {
  873.     if (flags[j]) {
  874.         if (first)
  875.           first = FALSE;
  876.         else
  877.           space_form();
  878.         fprintf(fp, "%s", escaped_symbol(name_from_typ(typ, j)));
  879.     }
  880.     }
  881.     if (listlen > 1)
  882.       end_form();
  883. }
  884.  
  885. #if 0
  886. /* Write out a list of values in a table. */
  887.  
  888. static void
  889. write_type_value_list(typ, flags, dim, getter, i)
  890. int typ, *flags, dim, (*getter) PARAMS ((int, int)), i;
  891. {
  892.     int j, first = TRUE, listlen = 0;
  893.  
  894.     for (j = 0; j < dim; ++j)
  895.       if (flags == NULL || flags[j])
  896.         ++listlen;
  897.     if (listlen > 1)
  898.       start_form("");
  899.     for (j = 0; j < dim; ++j) {
  900.     if (flags == NULL || flags[j]) {
  901.         if (first)
  902.           first = FALSE;
  903.         else
  904.           space_form();
  905.         fprintf(fp, "%d", (*getter)(i, j));
  906.     }
  907.     }
  908.     if (listlen > 1)
  909.       end_form();
  910. }
  911. #endif
  912.  
  913. /* A simple histogram struct - count and value, that's all. */
  914.  
  915. struct histo { int count, val; };
  916.  
  917. /* Sort into *descending* order by count. */
  918.  
  919. static int
  920. histo_compare(x, y)
  921. CONST void *x, *y;
  922. {
  923.     return ((struct histo *) y)->count - ((struct histo *) x)->count;
  924. }
  925.  
  926. /* Write out a single table.  Only write it if it contains non-default
  927.    values, and try to find runs of constant value, since tables can be
  928.    really large, but often have constant areas within them. */
  929.  
  930. static void
  931. write_table(name, getter, dflt, typ1, typ2, compress)
  932. char *name;
  933. int (*getter) PARAMS ((int, int)), dflt, typ1, typ2, compress;
  934. {
  935.     int i, j, k, colvalue, constcol, next;
  936.     int numrandoms, nextrowdiffers, writeconst;
  937.     int sawfirst, constrands, constval;
  938.     int dim1 = numtypes_from_index_type(typ1);
  939.     int dim2 = numtypes_from_index_type(typ2);
  940.     struct histo mostcommon[200]; /* needs to be more than MAXxTYPES */
  941.     int indexes1[200], randoms[200];
  942.  
  943.     start_form(key(K_TABLE));
  944.     add_to_form(name);
  945.     fprintf(fp, "  ; %d", dflt);
  946.     if (!compress) {
  947.     /* Write every value separately. */
  948.     for (i = 0; i < dim1; ++i) {
  949.         newline_form();
  950.         space_form();
  951.         space_form();
  952.         start_form(escaped_symbol(name_from_typ(typ1, i)));
  953.         add_to_form(star_from_typ(typ2));
  954.         space_form();
  955.         start_form("");
  956.         for (j = 0; j < dim2; ++j) {
  957.         add_num_to_form((*getter)(i, j));
  958.         }
  959.         end_form();
  960.         end_form();
  961.     }
  962.     } else if (dim1 <= dim2) {
  963.         /* Analyze the table by rows. */
  964.     for (k = 0; k < dim1; ++k)
  965.       indexes1[k] = FALSE;
  966.     for (i = 0; i < dim1; ++i) {
  967.         /* First see if this row has all the same values as the next. */
  968.         indexes1[i] = TRUE;
  969.         nextrowdiffers = FALSE;
  970.         if (i < dim1 - 1) {
  971.             for (j = 0; j < dim2; ++j) {
  972.                 if ((*getter)(i, j) != (*getter)(i + 1, j)) {
  973.                     nextrowdiffers = TRUE;
  974.                     break;
  975.                 }
  976.             }
  977.         } else {
  978.             /* The last row is *always* "different". */
  979.             nextrowdiffers = TRUE;
  980.         }
  981.         /* (should look at *all* rows to find matching rows before
  982.            dumping one) */
  983.         if (nextrowdiffers) {
  984.         /* Make a histogram of all the values in this row. */
  985.         mostcommon[0].count = 1;
  986.         mostcommon[0].val = (*getter)(i, 0);
  987.         next = 1;
  988.         for (j = 0; j < dim2; ++j) {
  989.             for (k = 0; k < next; ++k) {
  990.             if (mostcommon[k].val == (*getter)(i, j)) {
  991.                 ++(mostcommon[k].count);
  992.                 break;
  993.             }
  994.             }
  995.             if (k == next) {
  996.             mostcommon[next].count = 1;
  997.             mostcommon[next].val = (*getter)(i, j);
  998.             ++next;
  999.             }
  1000.         }
  1001.         if (next == 1 && mostcommon[0].val == dflt) {
  1002.             /* Entire row(s) is/are just the default table value. */
  1003.         } else {
  1004.             writeconst = FALSE;
  1005.             numrandoms = 0;
  1006.             if (next == 1) {
  1007.             /* Only one value in the row(s). */
  1008.             writeconst = TRUE;
  1009.             } else {
  1010.             qsort(mostcommon, next, sizeof(struct histo),
  1011.                   histo_compare);
  1012.             if (mostcommon[0].count >= (3 * dim2) / 4) {
  1013.                 /* The most common value in this row(s) is not the only value,
  1014.                    but it is worth writing into a separate clause. */
  1015.                 writeconst = TRUE;
  1016.                 for (j = 0; j < dim2; ++j) {
  1017.                 /* Flag the other values as needing to be
  1018.                    written separately. */
  1019.                 randoms[j] =
  1020.                   (mostcommon[0].val != (*getter)(i, j));
  1021.                 if (randoms[j])
  1022.                   ++numrandoms;
  1023.                 }
  1024.             } else {
  1025.                 /* Flag all in the row as randoms. */
  1026.                 for (j = 0; j < dim2; ++j) {
  1027.                 randoms[j] = TRUE;
  1028.                 ++numrandoms;
  1029.                 }
  1030.             }
  1031.             }
  1032.             /* Write out the most common value (if non-default) in the row(s),
  1033.                expressing it with a clause that applies the value
  1034.                to the entire row(s). */
  1035.             if (writeconst && mostcommon[0].val != dflt) {
  1036.             newline_form();
  1037.             space_form();
  1038.             space_form();
  1039.             start_form("");
  1040.             write_type_name_list(typ1, indexes1, dim1);
  1041.             add_to_form(star_from_typ(typ2));
  1042.             add_num_to_form(mostcommon[0].val);
  1043.             end_form();
  1044.             }
  1045.             /* Now override the most common value with any
  1046.                exceptions. */
  1047.             if (numrandoms > 0) {
  1048.             constrands = TRUE;
  1049.             sawfirst = FALSE;
  1050.             for (j = 0; j < dim2; ++j) {
  1051.                 if (randoms[j]) {
  1052.                     if (!sawfirst) {
  1053.                     constval = (*getter)(i, j);
  1054.                     sawfirst = TRUE;
  1055.                     }
  1056.                     if (sawfirst && constval != (*getter)(i, j)) {
  1057.                     constrands = FALSE;
  1058.                     break;
  1059.                     }
  1060.                 }
  1061.             }
  1062.             if (constrands) {
  1063.                 newline_form();
  1064.                 space_form();
  1065.                 space_form();
  1066.                 start_form("");
  1067.                 write_type_name_list(typ1, indexes1, dim1);
  1068.                 space_form();
  1069.                 write_type_name_list(typ2, randoms, dim2);
  1070.                 add_num_to_form(constval);
  1071.                 end_form();
  1072.             } else {
  1073.                 /* We have a group of rows with varying data
  1074.                    in the columns; write a separate row. */
  1075.                 for (j = 0; j < dim2; ++j) {
  1076.                 if (randoms[j]) {
  1077.                     newline_form();
  1078.                     space_form();
  1079.                     space_form();
  1080.                     start_form("");
  1081.                     write_type_name_list(typ1, indexes1, dim1);
  1082.                     add_to_form(escaped_symbol(name_from_typ(typ2, j)));
  1083.                     add_num_to_form((*getter)(i, j));
  1084.                     end_form();
  1085.                 }
  1086.                 }
  1087.             }
  1088.             }
  1089.         }
  1090.         /* Reset the row flags in preparation for the next group
  1091.            of rows whose contents match each other. */
  1092.         for (k = 0; k < dim1; ++k)
  1093.           indexes1[k] = FALSE;
  1094.         }
  1095.     }
  1096.     } else {
  1097.         /* Analyze the table by columns. */
  1098.         /* Don't work as hard to optimize; this case should be uncommon,
  1099.        since there are usually more types of units than
  1100.        materials or terrain. */
  1101.     for (j = 0; j < dim2; ++j) {
  1102.         constcol = TRUE;
  1103.         colvalue = (*getter)(0, j);
  1104.         for (i = 0; i < dim1; ++i) {
  1105.         if ((*getter)(i, j) != colvalue) {
  1106.             constcol = FALSE;
  1107.             break;
  1108.         }
  1109.         }
  1110.         if (!constcol || colvalue != dflt) {
  1111.         newline_form();
  1112.         space_form();
  1113.         space_form();
  1114.         start_form(star_from_typ(typ1));
  1115.         add_to_form(escaped_symbol(name_from_typ(typ2, j)));
  1116.         /* Write out either a single constant value or a list of
  1117.            varying values, as appropriate. */
  1118.         if (constcol) {
  1119.             add_num_to_form(colvalue);
  1120.         } else {
  1121.             space_form();
  1122.             start_form("");
  1123.             for (i = 0; i < dim1; ++i) {
  1124.             add_num_to_form((*getter)(i, j));
  1125.             }
  1126.             end_form();
  1127.         }
  1128.         end_form();
  1129.         }
  1130.     }
  1131.     }
  1132.     newline_form();
  1133.     space_form();
  1134.     space_form();
  1135.     end_form();
  1136.     newline_form();
  1137. }
  1138.  
  1139. /* Write info about the whole world. */
  1140.  
  1141. static void
  1142. write_world()
  1143. {
  1144.     newline_form();
  1145.     start_form(key(K_WORLD));
  1146.     /* K_CIRCUMFERENCE always written. */
  1147.     add_num_to_form((doreshape ? reshaper->final_circumference : world.circumference));
  1148.     write_num_prop(key(K_DAY_LENGTH), world.daylength, 1, FALSE, FALSE);
  1149.     write_num_prop(key(K_YEAR_LENGTH), world.yearlength, 1, FALSE, FALSE);
  1150.     write_num_prop(key(K_AXIAL_TILT), world.axialtilt, 0, FALSE, FALSE);
  1151.     end_form();
  1152.     newline_form();
  1153. }
  1154.  
  1155. /* Write info about the area in the world.  This code uses run-length encoding
  1156.    to reduce the size of each written layer as much as possible.  Note
  1157.    also that each layer is written as a separate form, so that the Lisp
  1158.    reader doesn't have to read really large forms back in. */
  1159.  
  1160. static void
  1161. write_areas(module)
  1162. Module *module;
  1163. {
  1164.     int all = module->def_all, compress = module->compress_layers;
  1165.  
  1166.     newline_form();
  1167.     /* Write the basic dimensions. */
  1168.     start_form(key(K_AREA));
  1169.     /* K_WIDTH, K_HEIGHT always written. */
  1170.     add_num_to_form((doreshape ? reshaper->final_width : area.width));
  1171.     add_num_to_form((doreshape ? reshaper->final_height : area.height));
  1172.     /* Write all the scalar properties. */
  1173.     write_num_prop(key(K_LATITUDE), area.latitude, 0, 0, FALSE);
  1174.     write_num_prop(key(K_LONGITUDE), area.longitude, 0, 0, FALSE);
  1175.     write_num_prop(key(K_CELL_WIDTH), area.cellwidth, 0, 0, FALSE);
  1176.     end_form();
  1177.     newline_form();
  1178.     /* Write the area's layers, each as a separate form. */
  1179.     if (all || module->def_area_terrain)
  1180.       write_area_terrain(compress);
  1181.     if (all || module->def_area_terrain)
  1182.       write_area_aux_terrain(compress);
  1183.     if (all || module->def_area_misc)
  1184.       write_area_features(compress);
  1185.     if (all || module->def_area_misc)
  1186.       write_area_elevations(compress);
  1187.     if (all || module->def_area_misc)
  1188.       write_area_people_sides(compress);
  1189.     if (all || module->def_area_material)
  1190.       write_area_materials(compress);
  1191.     if (all || module->def_area_weather)
  1192.       write_area_temperatures(compress);
  1193.     if (all || module->def_area_weather)
  1194.       write_area_clouds(compress);
  1195.     if (all || module->def_area_weather)
  1196.       write_area_winds(compress);
  1197. }
  1198.  
  1199. static void
  1200. write_area_terrain(compress)
  1201. int compress;
  1202. {
  1203.     int t;
  1204.  
  1205.     start_form(key(K_AREA));
  1206.     space_form();
  1207.     start_form(key(K_TERRAIN));
  1208.     newline_form();
  1209.     space_form();
  1210.     start_form(key(K_BY_NAME));
  1211.     for_all_terrain_types(t) {
  1212.     /* Break the list into groups of 5 per line. */
  1213.         if (t % 5 == 0) {
  1214.         newline_form();
  1215.         space_form();
  1216.         space_form();
  1217.         space_form();
  1218.     }
  1219.     space_form();
  1220.     start_form(escaped_symbol(t_type_name(t)));
  1221.     add_num_to_form(t);
  1222.     end_form();
  1223.     }
  1224.     end_form();
  1225.     newline_form();
  1226.     write_rle(fn_terrain_at, 0, numttypes - 1, NULL, compress);
  1227.     space_form();
  1228.     space_form();
  1229.     end_form();
  1230.     end_form();
  1231.     newline_form();
  1232. }
  1233.  
  1234. static void
  1235. write_area_aux_terrain(compress)
  1236. int compress;
  1237. {
  1238.     int t;
  1239.  
  1240.     for_all_terrain_types(t) {
  1241.     if (aux_terrain_defined(t)) {
  1242.         start_form(key(K_AREA));
  1243.         space_form();
  1244.         start_form(key(K_AUX_TERRAIN));
  1245.         add_to_form(escaped_symbol(t_type_name(t)));
  1246.         newline_form();
  1247.         tmpttype = t;
  1248.         write_rle(fn_aux_terrain_at, 0, 127, NULL, compress);
  1249.         space_form();
  1250.         space_form();
  1251.         end_form();
  1252.         end_form();
  1253.         newline_form();
  1254.     }
  1255.     }
  1256. }
  1257.  
  1258. static void
  1259. write_area_features(compress)
  1260. int compress;
  1261. {
  1262.     Feature *feature;
  1263.  
  1264.     if (featurelist == NULL || !features_defined())
  1265.       return;
  1266.     start_form(key(K_AREA));
  1267.     space_form();
  1268.     start_form(key(K_FEATURES));
  1269.     space_form();
  1270.     start_form("");
  1271.     newline_form();
  1272.     /* Dump out the list of features first. */
  1273.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1274.     space_form();
  1275.     space_form();
  1276.     space_form();
  1277.     start_form("");
  1278.     add_num_to_form(feature->id);
  1279.     add_to_form(escaped_string(feature->typename));
  1280.     add_to_form(escaped_string(feature->name));
  1281.     end_form();
  1282.     newline_form();
  1283.     }
  1284.     space_form();
  1285.     space_form();
  1286.     end_form();
  1287.     newline_form();
  1288.     /* Now record which features go with which cells. */
  1289.     write_rle(fn_feature_at, 0, -1, NULL, compress);
  1290.     space_form();
  1291.     space_form();
  1292.     end_form();
  1293.     end_form();
  1294.     newline_form();
  1295. }
  1296.  
  1297. static int
  1298. fn_elevation_at_offset(x, y)
  1299. int x, y;
  1300. {
  1301.     return (elev_at(x, y) - area.minelev);
  1302. }
  1303.  
  1304. static void
  1305. write_area_elevations(compress)
  1306. int compress;
  1307. {
  1308.     if (!elevations_defined())
  1309.       return;
  1310.     start_form(key(K_AREA));
  1311.     space_form();
  1312.     start_form(key(K_ELEVATIONS));
  1313.     if (area.minelev != 0) {
  1314.     space_form();
  1315.     start_form(key(K_XFORM));
  1316.     add_num_to_form(1);
  1317.     add_num_to_form(area.minelev);
  1318.     end_form();
  1319.     }
  1320.     newline_form();
  1321.     write_rle(fn_elevation_at_offset, minelev - area.minelev, maxelev, NULL, compress);
  1322.     space_form();
  1323.     space_form();
  1324.     end_form();
  1325.     end_form();
  1326.     newline_form();
  1327. }
  1328.  
  1329. /* Write out people sides for the area. */
  1330.  
  1331. static void
  1332. write_area_people_sides(compress)
  1333. int compress;
  1334. {
  1335.     Side *side;
  1336.  
  1337.     if (!people_sides_defined())
  1338.       return;
  1339.     start_form(key(K_AREA));
  1340.     space_form();
  1341.     start_form(key(K_PEOPLE_SIDES));
  1342.     newline_form();
  1343.     space_form();
  1344.     space_form();
  1345.     start_form(key(K_BY_NAME));
  1346.     for_all_sides(side) {
  1347.     /* Break the list into groups of 5 per line. */
  1348.     if (side_number(side) % 5 == 0) {
  1349.         newline_form();
  1350.         space_form();
  1351.         space_form();
  1352.         space_form();
  1353.     }
  1354.     space_form();
  1355.     start_form("");
  1356.     add_num_to_form(side_number(side)); /* should be symbol */
  1357.     add_num_to_form(side_number(side));
  1358.     end_form();
  1359.     }
  1360.     end_form();
  1361.     newline_form();
  1362.     /* Value of NOBODY is guaranteed to be the largest valid. */
  1363.     write_rle(fn_people_side_at, 0, NOBODY, NULL, compress);
  1364.     space_form();
  1365.     space_form();
  1366.     end_form();
  1367.     end_form();
  1368.     newline_form();
  1369. }
  1370.  
  1371. static void
  1372. write_area_materials(compress)
  1373. int compress;
  1374. {
  1375.     int m;
  1376.  
  1377.     if (any_cell_materials_defined()) {
  1378.     for_all_material_types(m) {
  1379.         if (cell_material_defined(m)) {
  1380.         start_form(key(K_AREA));
  1381.         space_form();
  1382.         start_form(key(K_MATERIAL));
  1383.         add_to_form(escaped_symbol(m_type_name(m)));
  1384.         newline_form();
  1385.         tmpmtype = m;
  1386.         write_rle(fn_material_at, 0, 127, NULL, compress);
  1387.         end_form();
  1388.         end_form();
  1389.         newline_form();
  1390.         }
  1391.     }
  1392.     }
  1393. }
  1394.  
  1395. static void
  1396. write_area_temperatures(compress)
  1397. int compress;
  1398. {
  1399.     if (!temperatures_defined())
  1400.       return;
  1401.     start_form(key(K_AREA));
  1402.     space_form();
  1403.     start_form(key(K_TEMPERATURES));
  1404.     newline_form();
  1405.     write_rle(fn_temperature_at, 0, 9999, NULL, compress);
  1406.     space_form();
  1407.     space_form();
  1408.     end_form();
  1409.     end_form();
  1410.     newline_form();
  1411. }
  1412.  
  1413. static void
  1414. write_area_clouds(compress)
  1415. int compress;
  1416. {
  1417.     if (clouds_defined()) {
  1418.     start_form(key(K_AREA));
  1419.     space_form();
  1420.     start_form(key(K_CLOUDS));
  1421.     newline_form();
  1422.     write_rle(fn_raw_cloud_at, 0, 127, NULL, compress);
  1423.     space_form();
  1424.     space_form();
  1425.     end_form();
  1426.     end_form();
  1427.     newline_form();
  1428.     }
  1429.     if (cloud_bottoms_defined()) {
  1430.     start_form(key(K_AREA));
  1431.     space_form();
  1432.     start_form(key(K_CLOUD_BOTTOMS));
  1433.     newline_form();
  1434.     write_rle(fn_raw_cloud_bottom_at, 0, 9999, NULL, compress);
  1435.     space_form();
  1436.     space_form();
  1437.     end_form();
  1438.     end_form();
  1439.     newline_form();
  1440.     }
  1441.     if (cloud_heights_defined()) {
  1442.     start_form(key(K_AREA));
  1443.     space_form();
  1444.     start_form(key(K_CLOUD_HEIGHTS));
  1445.     newline_form();
  1446.     write_rle(fn_raw_cloud_height_at, 0, 9999, NULL, compress);
  1447.     space_form();
  1448.     space_form();
  1449.     end_form();
  1450.     end_form();
  1451.     newline_form();
  1452.     }
  1453. }
  1454.  
  1455. static void
  1456. write_area_winds(compress)
  1457. int compress;
  1458. {
  1459.     if (winds_defined()) {
  1460.     start_form(key(K_AREA));
  1461.     space_form();
  1462.     start_form(key(K_WINDS));
  1463.     newline_form();
  1464.     write_rle(fn_raw_wind_at, -32767, 32767, NULL, compress);
  1465.     space_form();
  1466.     space_form();
  1467.     end_form();
  1468.     end_form();
  1469.     newline_form();
  1470.     }
  1471. }
  1472.  
  1473. /* Write the globals.  The "complete" flag forces all values out, even
  1474.    if they match the compiled-in defaults. */
  1475.  
  1476. static void
  1477. write_globals()
  1478. {
  1479.     int i, complete = FALSE;
  1480.     time_t now;
  1481.  
  1482.     /* Snapshot realtime values. */
  1483.     time(&now);
  1484.     set_g_elapsed_time(idifftime(now, game_start_in_real_time));
  1485.  
  1486.     newline_form();
  1487.  
  1488.     for (i = 0; vardefns[i].name != 0; ++i) {
  1489.     if (vardefns[i].intgetter != NULL) {
  1490.         if (complete || (*(vardefns[i].intgetter))() != vardefns[i].dflt) {
  1491.         start_form(key(K_SET));
  1492.         add_to_form(vardefns[i].name);
  1493.         add_num_to_form((*(vardefns[i].intgetter))());
  1494.         end_form();
  1495.         newline_form();
  1496.         }
  1497.     } else if (vardefns[i].strgetter != NULL) {
  1498.         if (complete || string_not_default((*(vardefns[i].strgetter))(), vardefns[i].dfltstr)) {
  1499.         start_form(key(K_SET));
  1500.         add_to_form(vardefns[i].name);
  1501.         add_to_form(escaped_string((*(vardefns[i].strgetter))()));
  1502.         end_form();
  1503.         newline_form();
  1504.         }
  1505.     } else if (vardefns[i].objgetter != NULL) {
  1506.         if (complete
  1507.         || (vardefns[i].dfltfn == NULL
  1508.             && (*(vardefns[i].objgetter))() != lispnil)) {
  1509.         if ((*(vardefns[i].objgetter))() != NULL) {
  1510.             start_form(key(K_SET));
  1511.             add_to_form(vardefns[i].name);
  1512.             space_form();
  1513.             /* Suppress evaluation upon readin. */
  1514.             fprintf(fp, "'");
  1515.             fprintlisp(fp, (*(vardefns[i].objgetter))());
  1516.             end_form();
  1517.             newline_form();
  1518.         } else {
  1519.             fprintf(fp, "; %s was unbound?\n", vardefns[i].name);
  1520.         }
  1521.         }
  1522.     } else {
  1523.         abort();
  1524.     }
  1525.     }
  1526. }
  1527.  
  1528. /* Write all the scorekeepers. */
  1529.  
  1530. static void
  1531. write_scorekeepers()
  1532. {
  1533.     Scorekeeper *sk;
  1534.  
  1535.     for_all_scorekeepers(sk) {
  1536.     start_form(key(K_SCOREKEEPER));
  1537.     add_num_to_form(sk->id);
  1538.     newline_form();
  1539.     space_form();
  1540.     write_str_prop(key(K_TITLE), sk->title, "", FALSE, TRUE);
  1541.     write_lisp_prop(key(K_WHEN), sk->when, lispnil, FALSE, FALSE, TRUE);
  1542.     write_lisp_prop(key(K_APPLIES_TO), sk->who, lispnil, FALSE, FALSE, TRUE);
  1543.     write_lisp_prop(key(K_KNOWN_TO), sk->who, lispnil, FALSE, FALSE, TRUE);
  1544.     write_lisp_prop(key(K_TRIGGER), sk->trigger, lispnil, FALSE, FALSE, TRUE);
  1545.     write_lisp_prop(key(K_DO), sk->body, lispnil, FALSE, FALSE, TRUE);
  1546.     write_num_prop(key(K_TRIGGERED), sk->triggered, 0, FALSE, TRUE); 
  1547.     write_num_prop(key(K_INITIAL), sk->initial, -10001, FALSE, TRUE); 
  1548.     write_lisp_prop(key(K_NOTES), sk->notes, lispnil, FALSE, FALSE, TRUE);
  1549.     space_form();
  1550.     end_form();
  1551.     newline_form();
  1552.     }
  1553. }
  1554.  
  1555. static void
  1556. write_doctrines()
  1557. {
  1558.     Doctrine *doc;
  1559.  
  1560.     for (doc = doctrine_list; doc != NULL; doc = doc->next) {
  1561.     start_form(key(K_DOCTRINE));
  1562.     if (doc->name)
  1563.       add_to_form(escaped_symbol(doc->name));
  1564.     else
  1565.       add_num_to_form(doc->id);
  1566.     newline_form();
  1567.     space_form();
  1568.     write_num_prop(key(K_EVER_ASK_SIDE), doc->everaskside, 0, FALSE, TRUE); 
  1569.     write_utype_value_list(key(K_CONSTRUCTION_RUN), doc->construction_run, 0, TRUE);
  1570.     write_num_prop(key(K_LOCKED), doc->locked, 0, FALSE, TRUE); 
  1571.     space_form();
  1572.     end_form();
  1573.     newline_form();
  1574.     }
  1575. }
  1576.  
  1577. /* Write declarations of all the sides. */
  1578.  
  1579. static void
  1580. write_sides(module)
  1581. Module *module;
  1582. {
  1583.     Side *side;
  1584.  
  1585.     fprintf(fp, "\n; %d sides\n", numsides);
  1586.     Dprintf("Will try to write %d sides ...\n", numsides);
  1587.     for_all_sides(side) {
  1588.     start_form(key(K_SIDE));
  1589.     add_num_to_form(side->id);
  1590.     if (symbolp(side->symbol))
  1591.       add_to_form(escaped_symbol(c_string(side->symbol)));
  1592.     newline_form();
  1593.     space_form();
  1594.     write_side_properties(side);
  1595.     space_form();
  1596.     end_form();
  1597.     newline_form();
  1598.     if (module->def_all || module->def_side_views)
  1599.       write_side_view(side, module->compress_layers);
  1600.     Dprintf("  Wrote side %s\n", side_desig(side));
  1601.     }
  1602.     start_form(key(K_INDEPENDENT_UNITS));
  1603.     newline_form();
  1604.     write_side_properties(indepside);
  1605.     space_form();
  1606.     end_form();
  1607.     newline_form();
  1608.     Dprintf("  Wrote independent unit properties\n");
  1609.     Dprintf("... Done writing sides\n");
  1610. }
  1611.  
  1612. /* Write random properties of a side. */
  1613.  
  1614. static void
  1615. write_side_properties(side)
  1616. Side *side;
  1617. {
  1618.     int i, u, u2, anyudoctrines;
  1619.  
  1620.     write_str_prop(key(K_NAME), side->name, "", FALSE, TRUE);
  1621.     write_str_prop(key(K_LONG_NAME), side->longname, "", FALSE, TRUE);
  1622.     write_str_prop(key(K_SHORT_NAME), side->shortname, "", FALSE, TRUE);
  1623.     write_str_prop(key(K_NOUN), side->noun, "", FALSE, TRUE);
  1624.     write_str_prop(key(K_PLURAL_NOUN), side->pluralnoun, "", FALSE, TRUE);
  1625.     write_str_prop(key(K_ADJECTIVE), side->adjective, "", FALSE, TRUE);
  1626.     write_str_prop(key(K_COLOR), side->colorscheme, "", FALSE, TRUE);
  1627.     write_str_prop(key(K_EMBLEM_NAME), side->emblemname, "", FALSE, TRUE);
  1628.     write_utype_string_list(key(K_UNIT_NAMERS), side->unitnamers, "", TRUE);
  1629.     write_str_prop(key(K_CLASS), side->sideclass, "", FALSE, TRUE);
  1630.     write_bool_prop(key(K_ACTIVE), side->ingame, 1, FALSE, TRUE);
  1631.     write_bool_prop(key(K_EVER_ACTIVE), side->everingame, 1, FALSE, TRUE);
  1632.     write_num_prop(key(K_PRIORITY), side->priority, 0, FALSE, TRUE);
  1633.     write_num_prop(key(K_STATUS), side->status, 0, FALSE, TRUE);
  1634.     write_num_prop(key(K_TURN_TIME_USED), side->turntimeused, 0, FALSE, TRUE);
  1635.     write_num_prop(key(K_TOTAL_TIME_USED), side->totaltimeused, 0, FALSE, TRUE);
  1636.     write_num_prop(key(K_TIMEOUTS), side->timeouts, 0, FALSE, TRUE);
  1637.     write_num_prop(key(K_TIMEOUTS_USED), side->timeoutsused, 0, FALSE, TRUE);
  1638.     write_num_prop(key(K_FINISHED_TURN), side->finishedturn, 0, FALSE, TRUE);
  1639.     write_num_prop(key(K_WILLING_TO_DRAW), side->willingtodraw, 0, FALSE, TRUE);
  1640.     write_num_prop(key(K_ADVANTAGE), side->advantage, 1, FALSE, TRUE);
  1641.     write_num_prop(key(K_ADVANTAGE_MIN), side->minadvantage, 1, FALSE, TRUE);
  1642.     write_num_prop(key(K_ADVANTAGE_MAX), side->maxadvantage, 9999, FALSE, TRUE);
  1643.     write_num_prop(key(K_CONTROLLED_BY), side_number(side->controlled_by), 0, FALSE, TRUE);
  1644.     write_num_prop(key(K_SELF_UNIT), (side->self_unit ? side->self_unit->id : 0), 0, FALSE, TRUE);
  1645.     write_num_prop(key(K_PLAYER), (side->player ? side->player->id : 0), 0, FALSE, TRUE);
  1646.     write_num_prop(key(K_DEFAULT_DOCTRINE),
  1647.                (side->default_doctrine ? side->default_doctrine->id : 0), 0, FALSE, TRUE);
  1648.     anyudoctrines = FALSE;
  1649.     for_all_unit_types(u) {
  1650.     if (side->udoctrine[u] != side->default_doctrine) {
  1651.         anyudoctrines = TRUE;
  1652.         break;
  1653.     }
  1654.     }
  1655.     if (anyudoctrines) {
  1656.     space_form();
  1657.     start_form(key(K_DOCTRINES));
  1658.     for_all_unit_types(u) {
  1659.         if (side->udoctrine[u] != side->default_doctrine) {
  1660.         space_form();
  1661.         start_form(escaped_symbol(u_type_name(u)));
  1662.         if (side->udoctrine[u]->name)
  1663.           add_to_form(escaped_symbol(side->udoctrine[u]->name));
  1664.         else
  1665.           add_num_to_form(side->udoctrine[u]->id);
  1666.         end_form();
  1667.         }
  1668.     }
  1669.     end_form();
  1670.     newline_form();
  1671.     space_form();
  1672.     }
  1673.     write_side_value_list(key(K_TRUSTS), side->trusts, FALSE, TRUE);
  1674.     write_side_value_list(key(K_TRADES), side->trades, FALSE, TRUE);
  1675.     write_utype_value_list(key(K_START_WITH), side->startwith, 0, TRUE);
  1676.     write_utype_value_list(key(K_NEXT_NUMBERS), side->counts, 0, TRUE);
  1677.     write_utype_value_list(key(K_TECH), side->tech, 0, TRUE);
  1678.     write_utype_value_list(key(K_INIT_TECH), side->inittech, 0, TRUE);
  1679.     if (side->scores) {
  1680.     space_form();
  1681.     start_form(key(K_SCORES));
  1682.     for (i = 0; i < numscores; ++i) {
  1683.         add_num_to_form(side->scores[i]);
  1684.     }
  1685.     end_form();
  1686.     newline_form();
  1687.     space_form();
  1688.     }
  1689.     /* Write out statistics. */
  1690.     if (side->gaincounts != NULL) {
  1691.     space_form();
  1692.     start_form(key(K_GAIN_COUNTS));
  1693.     for (i = 0; i < numutypes * num_gain_reasons; ++i) {
  1694.         add_num_to_form(side->gaincounts[i]);
  1695.     }
  1696.     end_form();
  1697.     newline_form();
  1698.     space_form();
  1699.     }
  1700.     if (side->losscounts != NULL) {
  1701.     space_form();
  1702.     start_form(key(K_LOSS_COUNTS));
  1703.     for (i = 0; i < numutypes * num_loss_reasons; ++i) {
  1704.         add_num_to_form(side->losscounts[i]);
  1705.     }
  1706.     end_form();
  1707.     newline_form();
  1708.     space_form();
  1709.     }
  1710.     if (side->atkstats != NULL) {
  1711.     space_form();
  1712.     start_form(key(K_ATTACK_STATS));
  1713.     for_all_unit_types(u) {
  1714.         if (side->atkstats[u] != NULL) {
  1715.         newline_form();
  1716.         space_form();
  1717.         space_form();
  1718.         space_form();
  1719.         start_form(u_type_name(u));
  1720.         for_all_unit_types(u2) {
  1721.             add_num_to_form(side_atkstats(side, u, u2));
  1722.         }
  1723.         end_form();
  1724.         }
  1725.     }
  1726.     end_form();
  1727.     newline_form();
  1728.     space_form();
  1729.     }
  1730.     if (side->hitstats != NULL) {
  1731.     space_form();
  1732.     start_form(key(K_HIT_STATS));
  1733.     for_all_unit_types(u) {
  1734.         if (side->hitstats[u] != NULL) {
  1735.         newline_form();
  1736.         space_form();
  1737.         space_form();
  1738.         space_form();
  1739.         start_form(u_type_name(u));
  1740.         for_all_unit_types(u2) {
  1741.             add_num_to_form(side_hitstats(side, u, u2));
  1742.         }
  1743.         end_form();
  1744.         }
  1745.     }
  1746.     end_form();
  1747.     newline_form();
  1748.     space_form();
  1749.     }
  1750.     /* Have the AI paste its useful state into distinct element of
  1751.        side->aidata. */
  1752.     if (side_has_ai(side)) {
  1753.     ai_save_state(side);
  1754.     }
  1755.     write_lisp_prop(key(K_AI_DATA), side->aidata, lispnil, FALSE, TRUE, TRUE);
  1756.     /* Have the interface paste its useful state into distinct element
  1757.        of side->uidata. */
  1758.     if (side_has_display(side)) {
  1759.     ui_save_state(side);
  1760.     }
  1761.     write_lisp_prop(key(K_UI_DATA), side->uidata, lispnil, FALSE, TRUE, TRUE);
  1762. }
  1763.  
  1764. /* Write about what has been seen in the area. */
  1765.  
  1766. /* (should have option to spec symbolic dict of sides and units) */
  1767.  
  1768. static int
  1769. fn_terrain_view(x, y)
  1770. int x, y;
  1771. {
  1772.     return terrain_view(tmpside, x, y);
  1773. }
  1774.  
  1775. static int
  1776. fn_terrain_view_date(x, y)
  1777. int x, y;
  1778. {
  1779.     return terrain_view_date(tmpside, x, y);
  1780. }
  1781.  
  1782. static int
  1783. fn_aux_terrain_view(x, y)
  1784. int x, y;
  1785. {
  1786.     return aux_terrain_view(tmpside, x, y, tmpttype);
  1787. }
  1788.  
  1789. static int
  1790. fn_aux_terrain_view_date(x, y)
  1791. int x, y;
  1792. {
  1793.     return aux_terrain_view_date(tmpside, x, y, tmpttype);
  1794. }
  1795.  
  1796. static int
  1797. fn_unit_view(x, y)
  1798. int x, y;
  1799. {
  1800.     return unit_view(tmpside, x, y);
  1801. }
  1802.  
  1803. static int
  1804. fn_unit_view_date(x, y)
  1805. int x, y;
  1806. {
  1807.     return unit_view_date(tmpside, x, y);
  1808. }
  1809.  
  1810. static int
  1811. fn_material_view(x, y)
  1812. int x, y;
  1813. {
  1814.     return material_view(tmpside, x, y, tmpmtype);
  1815. }
  1816.  
  1817. static int
  1818. fn_material_view_date(x, y)
  1819. int x, y;
  1820. {
  1821.     return material_view_date(tmpside, x, y, tmpmtype);
  1822. }
  1823.  
  1824. static int
  1825. fn_temp_view(x, y)
  1826. int x, y;
  1827. {
  1828.     return temperature_view(tmpside, x, y);
  1829. }
  1830.  
  1831. static int
  1832. fn_temp_view_date(x, y)
  1833. int x, y;
  1834. {
  1835.     return temperature_view_date(tmpside, x, y);
  1836. }
  1837.  
  1838. static int
  1839. fn_cloud_view(x, y)
  1840. int x, y;
  1841. {
  1842.     return cloud_view(tmpside, x, y);
  1843. }
  1844.  
  1845. static int
  1846. fn_cloud_bottom_view(x, y)
  1847. int x, y;
  1848. {
  1849.     return cloud_bottom_view(tmpside, x, y);
  1850. }
  1851.  
  1852. static int
  1853. fn_cloud_height_view(x, y)
  1854. int x, y;
  1855. {
  1856.     return cloud_height_view(tmpside, x, y);
  1857. }
  1858.  
  1859. static int
  1860. fn_cloud_view_date(x, y)
  1861. int x, y;
  1862. {
  1863.     return cloud_view_date(tmpside, x, y);
  1864. }
  1865.  
  1866. static int
  1867. fn_wind_view(x, y)
  1868. int x, y;
  1869. {
  1870.     return wind_view(tmpside, x, y);
  1871. }
  1872.  
  1873. static int
  1874. fn_wind_view_date(x, y)
  1875. int x, y;
  1876. {
  1877.     return wind_view_date(tmpside, x, y);
  1878. }
  1879.  
  1880. static void
  1881. write_side_view(side, compress)
  1882. Side *side;
  1883. int compress;
  1884. {
  1885.     int t, m;
  1886.  
  1887.     /* View layers are not defined if see-all is in effect. */
  1888.     if (all_see_all)
  1889.       return;
  1890.     tmpside = side;
  1891.     tmpcompress = compress;
  1892.     write_one_side_view_layer(K_TERRAIN_VIEW, fn_terrain_view);
  1893.     if (!g_see_terrain_always()) {
  1894.     if (side->terrview)
  1895.       write_one_side_view_layer(K_TERRAIN_VIEW_DATES, fn_terrain_view_date);
  1896.     if (numcelltypes < numttypes) {
  1897.       for_all_terrain_types(t) {
  1898.         if (!t_is_cell(t)) {
  1899.         tmpttype = t;
  1900.         if (side->auxterrview[t])
  1901.           write_one_side_view_layer(K_AUX_TERRAIN_VIEW, fn_aux_terrain_view);
  1902.         if (side->auxterrviewdate[t])
  1903.           write_one_side_view_layer(K_AUX_TERRAIN_VIEW_DATES, fn_aux_terrain_view_date);
  1904.         }
  1905.       }
  1906.         }
  1907.     }
  1908.     if (0 /* have material views */) {
  1909.     for_all_material_types(m) {
  1910.         if (0) {
  1911.         tmpmtype = m;
  1912.         if (side->materialview[m])
  1913.           write_one_side_view_layer(K_MATERIAL_VIEW, fn_material_view);
  1914.         if (side->materialviewdate[m])
  1915.           write_one_side_view_layer(K_MATERIAL_VIEW_DATES, fn_material_view_date);
  1916.         }
  1917.     }
  1918.     }
  1919.     write_one_side_view_layer(K_UNIT_VIEW, fn_unit_view);
  1920.     write_one_side_view_layer(K_UNIT_VIEW_DATES, fn_unit_view_date);
  1921.     if (!g_see_weather_always()) {
  1922.       if (any_temp_variation) {
  1923.     write_one_side_view_layer(K_TEMPERATURE_VIEW, fn_temp_view);
  1924.     write_one_side_view_layer(K_TEMPERATURE_VIEW_DATES, fn_temp_view_date);
  1925.       }
  1926.       if (any_clouds) {
  1927.     write_one_side_view_layer(K_CLOUD_VIEW, fn_cloud_view);
  1928.     write_one_side_view_layer(K_CLOUD_BOTTOM_VIEW, fn_cloud_bottom_view);
  1929.     write_one_side_view_layer(K_CLOUD_HEIGHT_VIEW, fn_cloud_height_view);
  1930.     write_one_side_view_layer(K_CLOUD_VIEW_DATES, fn_cloud_view_date);
  1931.       }
  1932.       if (any_wind_variation) {
  1933.     write_one_side_view_layer(K_WIND_VIEW, fn_wind_view);
  1934.     write_one_side_view_layer(K_WIND_VIEW_DATES, fn_wind_view_date);
  1935.       }
  1936.     }
  1937. }
  1938.  
  1939. static void
  1940. write_one_side_view_layer(propkey, fn)
  1941. int propkey, (*fn) PARAMS ((int x, int y));
  1942. {
  1943.     newline_form();
  1944.     start_form(key(K_SIDE));
  1945.     add_num_to_form(tmpside->id);
  1946.     space_form();
  1947.     start_form(key(propkey));
  1948.     newline_form();
  1949.     write_rle(fn, -32767, 32767, NULL, tmpcompress);
  1950.     space_form();
  1951.     space_form();
  1952.     end_form();
  1953.     end_form();
  1954.     newline_form();
  1955. }
  1956.  
  1957. static void
  1958. write_players()
  1959. {
  1960.     Side *side;
  1961.  
  1962.     Dprintf("Will try to write players ...\n");
  1963.     for_all_sides(side) {
  1964.     if (side->player != NULL) {
  1965.         write_player(side->player);
  1966.         Dprintf("Wrote player %s,\n", player_desig(side->player));
  1967.     }
  1968.     }
  1969.     Dprintf("... Done writing players.\n");
  1970. }
  1971.  
  1972. static void
  1973. write_player(player)
  1974. Player *player;
  1975. {
  1976.     start_form(key(K_PLAYER));
  1977.     add_num_to_form(player->id);
  1978.     newline_form();
  1979.     space_form();
  1980.     write_str_prop(key(K_NAME), player->name, "", FALSE, TRUE);
  1981.     write_str_prop(key(K_CONFIG_NAME), player->configname, "", FALSE, TRUE);
  1982.     write_str_prop(key(K_DISPLAY_NAME), player->displayname, "", FALSE, TRUE);
  1983.     write_str_prop(key(K_AI_TYPE_NAME), player->aitypename, "", FALSE, TRUE);
  1984.     space_form();
  1985.     end_form();
  1986.     newline_form();
  1987. }
  1988.  
  1989. static void
  1990. write_agreements()
  1991. {
  1992.     Agreement *agreement;
  1993.  
  1994.     for (agreement = agreementlist; agreement != NULL; agreement = agreement->next) {
  1995.     write_agreement(agreement);
  1996.     }
  1997. }
  1998.  
  1999. static void
  2000. write_agreement(agreement)
  2001. Agreement *agreement;
  2002. {
  2003.     start_form(key(K_AGREEMENT));
  2004.     add_num_to_form(agreement->id);
  2005.     newline_form();
  2006.     space_form();
  2007.     write_str_prop(key(K_TYPE_NAME), agreement->typename, "", FALSE, TRUE);
  2008.     write_str_prop(key(K_NAME), agreement->name, "", FALSE, TRUE);
  2009.     write_num_prop(key(K_STATE), agreement->state, 0, FALSE, TRUE);
  2010.     write_lisp_prop(key(K_TERMS), agreement->terms, lispnil, FALSE, FALSE, TRUE);
  2011.     write_num_prop(key(K_DRAFTERS), agreement->drafters, 0, FALSE, TRUE);
  2012.     write_num_prop(key(K_PROPOSERS), agreement->proposers, 0, FALSE, TRUE);
  2013.     write_num_prop(key(K_SIGNERS), agreement->signers, 0, FALSE, TRUE);
  2014.     write_num_prop(key(K_WILLING_TO_SIGN), agreement->willing, 0, FALSE, TRUE);
  2015.     write_num_prop(key(K_KNOWN_TO), agreement->knownto, 0, FALSE, TRUE);
  2016.     write_num_prop(key(K_ENFORCEMENT), agreement->enforcement, 0, FALSE, TRUE);
  2017.     space_form();
  2018.     end_form();
  2019.     newline_form();
  2020. }
  2021.  
  2022. /* Should write out "unit groups" with dict prepended, then can use with
  2023.    multiple games */
  2024.  
  2025. /* Write the unit section of a game module. */
  2026.  
  2027. static void
  2028. write_units(module)
  2029. Module *module;
  2030. {
  2031.     int x0, y0, x, y, numtowrite;
  2032.     Unit *unit;
  2033.     Side *loopside;
  2034.  
  2035.     /* Make sure no dead units get saved. */
  2036.     flush_dead_units();
  2037.     /* Make a consistent ordering. */
  2038.     sort_units();
  2039.     numtowrite = 0;
  2040.     for_all_sides_plus_indep(loopside) {
  2041.     for_all_side_units(loopside, unit) {
  2042.         if (alive(unit))
  2043.           ++numtowrite;
  2044.     }
  2045.     }
  2046.     fprintf(fp, "; %d units\n", numtowrite);
  2047.     /* Need to write out the defaults being assumed subsequently. */
  2048.     /* maybe use those in postprocessing. */
  2049.     start_form(key(K_UNIT_DEFAULTS));
  2050.     end_form();
  2051.     newline_form();
  2052.     Dprintf("Writing %d units ...\n", numliveunits);
  2053.     for_all_sides_plus_indep(loopside) {
  2054.     for_all_side_units(loopside, unit) {
  2055.         if (alive(unit)) {
  2056.         /* K_AT always written */
  2057.         /* K_S always written */
  2058.         /* If the unit will appear later, must write out that
  2059.            later position, possibly mapped to a new place if
  2060.            the map is being reshaped. */
  2061.         if (unit->cp < 0 && unit_appear_turn(unit) >= 0) {
  2062.             x0 = (- unit->prevx);  y0 = (- unit->prevy);
  2063.         } else {
  2064.             x0 = unit->x;  y0 = unit->y;
  2065.         }
  2066.         if (doreshape) {
  2067.             reshaped_point(x0, y0, &x, &y);
  2068.         } else {
  2069.             x = x0;  y = y0;
  2070.         }
  2071.         /* If these were negative values made positive for the
  2072.            purposes of reshaping, make them negative again. */
  2073.         if (unit->cp < 0 && unit_appear_turn(unit) >= 0) {
  2074.             x = (- x);  y = (- y);
  2075.         }
  2076.         start_form(shortest_escaped_name(unit->type));
  2077.         add_num_to_form(x);
  2078.         add_num_to_form(y);
  2079.         /* (should be able to write sides symbolically) */
  2080.         add_num_to_form(side_number(unit->side));
  2081.         write_num_prop(key(K_Z), unit->z, 0, FALSE, FALSE);
  2082.         write_str_prop(key(K_N), unit->name, NULL, FALSE, FALSE);
  2083.         write_num_prop(key(K_OS), side_number(unit->origside), side_number(unit->side), FALSE, FALSE);
  2084.         /* Maybe write the unit's id. */
  2085.         if (module->def_all || module->def_unit_ids || unit->occupant)
  2086.           write_num_prop(key(K_SHARP), unit->id, 0, FALSE, FALSE);
  2087.         /* Need this to get back into the right transport. */
  2088.         if (unit->transport)
  2089.           write_num_prop(key(K_IN), unit->transport->id, 0, FALSE, FALSE);
  2090.         /* Write optional info about the units. */
  2091.         if (module->def_all || module->def_unit_props)
  2092.           write_unit_properties(unit);
  2093.         if (module->def_all || module->def_unit_acts)
  2094.           write_unit_act(unit);
  2095.         if (module->def_all || module->def_unit_plans)
  2096.           write_unit_plan(unit);
  2097.         /* close the unit out */
  2098.         end_form();
  2099.         newline_form();
  2100.         Dprintf("Wrote %s\n", unit_desig(unit));
  2101.         }
  2102.     }
  2103.     newline_form();
  2104.     }
  2105.     Dprintf("... Done writing units.\n");
  2106. }
  2107.  
  2108. /* Write random properties, but only if they have non-default values. */
  2109.  
  2110. static void
  2111. write_unit_properties(unit)
  2112. Unit *unit;
  2113. {
  2114.     write_num_prop(key(K_NB), unit->number, 0, FALSE, FALSE);
  2115.     write_num_prop(key(K_HP), unit->hp, u_hp(unit->type), FALSE, FALSE);
  2116.     write_num_prop(key(K_CP), unit->cp, u_cp(unit->type), FALSE, FALSE);
  2117.     write_num_prop(key(K_CXP), unit->cxp, 0, FALSE, FALSE);
  2118.     write_num_prop(key(K_MO), unit->morale, 0, FALSE, FALSE);
  2119.     write_utype_value_list(key(K_TP), unit->tooling, 0, FALSE);
  2120.     write_side_value_list(key(K_OPINIONS), unit->opinions, FALSE, FALSE);
  2121.     write_mtype_value_list(key(K_M), unit->supply, 0, FALSE);
  2122.     write_num_prop("point-value", unit_point_value(unit), -1, FALSE, FALSE);
  2123.     write_num_prop(key(K_APPEAR), unit_appear_turn(unit), -1, FALSE, FALSE);
  2124.     /* (should do appear x,y also here?) */
  2125.     write_num_prop(key(K_DISAPPEAR), unit_disappear_turn(unit), -1, FALSE, FALSE);
  2126.     write_lisp_prop(key(K_X), unit_hook(unit), lispnil, FALSE, TRUE, FALSE);
  2127. }
  2128.  
  2129. /* Write out the unit's current actor state. */
  2130.  
  2131. static void
  2132. write_unit_act(unit)
  2133. Unit *unit;
  2134. {
  2135.     int acp = u_acp(unit->type), atype, i, slen;
  2136.     ActorState *act = unit->act;
  2137.  
  2138.     /* Actor state is kind of meaningless for dead units. */
  2139.     if (!alive(unit))
  2140.       return;
  2141.     if (act != NULL
  2142.     && (act->acp != acp
  2143.         || act->initacp != acp
  2144.         || act->nextaction.type != ACTION_NONE)) {
  2145.     if (1) {
  2146.        newline_form();
  2147.        space_form();
  2148.     }
  2149.     space_form();
  2150.     start_form(key(K_ACT));
  2151.     if (act->acp != acp)
  2152.       write_num_prop(key(K_ACP), act->acp, acp, FALSE, FALSE);
  2153.     if (act->initacp != acp)
  2154.       write_num_prop(key(K_ACP0), act->initacp, acp, FALSE, FALSE);
  2155.     if (act->nextaction.type != ACTION_NONE) {
  2156.         atype = act->nextaction.type;
  2157.         space_form();
  2158.         start_form(key(K_A));
  2159.         add_to_form(actiondefns[atype].name);
  2160.         slen = strlen(actiondefns[atype].argtypes);
  2161.             for (i = 0; i < slen; ++i)
  2162.           add_num_to_form(act->nextaction.args[i]);
  2163.             if (act->nextaction.actee != 0) {
  2164.                 space_form();
  2165.         add_num_to_form(act->nextaction.actee);
  2166.             }
  2167.             end_form();
  2168.     }
  2169.     end_form();
  2170.     }
  2171. }
  2172.  
  2173. /* Write out the unit's current plan. */
  2174.  
  2175. static void
  2176. write_unit_plan(unit)
  2177. Unit *unit;
  2178. {
  2179.     Task *task;
  2180.     Plan *plan = unit->plan;
  2181.  
  2182.     /* The plan is kind of meaningless for dead units. */
  2183.     if (!alive(unit))
  2184.       return;
  2185.     if (plan) {
  2186.     if (1) {
  2187.         newline_form();
  2188.         space_form();
  2189.     }
  2190.         space_form();
  2191.         start_form(key(K_PLAN));
  2192.         add_to_form(plantypenames[plan->type]);
  2193.     add_num_to_form(plan->creation_turn);
  2194.     write_num_prop(key(K_INITIAL_TURN), plan->initial_turn, 0, FALSE, FALSE);
  2195.     write_num_prop(key(K_FINAL_TURN), plan->final_turn, 0, FALSE, FALSE);
  2196.     write_bool_prop(key(K_ASLEEP), plan->asleep, FALSE, FALSE, FALSE);
  2197.     write_bool_prop(key(K_RESERVE), plan->reserve, FALSE, FALSE, FALSE);
  2198.     write_bool_prop(key(K_DELAYED), plan->delayed, FALSE, FALSE, FALSE);
  2199.     write_bool_prop(key(K_WAIT), plan->waitingfortasks, FALSE, FALSE, FALSE);
  2200.     write_bool_prop(key(K_AI_CONTROL), plan->aicontrol, TRUE, FALSE, FALSE);
  2201.     write_bool_prop(key(K_SUPPLY_ALARM), plan->supply_alarm, TRUE, FALSE, FALSE);
  2202.     write_bool_prop(key(K_SUPPLY_IS_LOW), plan->supply_is_low, FALSE, FALSE, FALSE);
  2203.     write_bool_prop(key(K_WAIT_TRANSPORT), plan->waitingfortransport, FALSE, FALSE, FALSE);
  2204.     if (plan->maingoal)
  2205.       write_goal(plan->maingoal, K_GOAL);
  2206.     if (plan->formation)
  2207.       write_goal(plan->formation, K_FORMATION);
  2208.     if (plan->tasks) {
  2209.             space_form();
  2210.             start_form(key(K_TASKS));
  2211.             for_all_tasks(plan, task) {
  2212.             space_form();
  2213.             write_task(task);
  2214.         }
  2215.         end_form();
  2216.     }
  2217.     end_form();
  2218.     }
  2219. }
  2220.  
  2221. static void
  2222. write_task(task)
  2223. Task *task;
  2224. {
  2225.     int i, numargs;
  2226.     char *argtypes;
  2227.  
  2228.     /* (should make this into an "is_task_type" test) */
  2229.     if (!between(TASK_NONE, task->type, /*TASK_LAST*/ TASK_SENTRY)) {
  2230.     run_warning("Bad task type %d while writing, skipping it", task->type);
  2231.     return;
  2232.     }
  2233.     start_form(taskdefns[task->type].name);
  2234.     add_num_to_form(task->execnum);
  2235.     add_num_to_form(task->retrynum);
  2236.     argtypes = taskdefns[task->type].argtypes;
  2237.     numargs = strlen(argtypes);
  2238.     for (i = 0; i < numargs; ++i)
  2239.       add_num_to_form(task->args[i]);
  2240.     end_form();
  2241. }
  2242.  
  2243. static void
  2244. write_goal(goal, keyword)
  2245. Goal *goal;
  2246. int keyword;
  2247. {
  2248.     int i, numargs;
  2249.     char *argtypes;
  2250.  
  2251.     space_form();
  2252.     start_form(key(keyword));
  2253.     add_num_to_form(side_number(goal->side));
  2254.     add_num_to_form(goal->tf);
  2255.     add_to_form(goaldefns[goal->type].name);
  2256.     argtypes = goaldefns[goal->type].argtypes;
  2257.     numargs = strlen(argtypes);
  2258.     for (i = 0; i < numargs; ++i)
  2259.       add_num_to_form(goal->args[i]);
  2260.     end_form();
  2261. }
  2262.  
  2263. /* Write all the historical events recorded so far. */
  2264.  
  2265. static void
  2266. write_history()
  2267. {
  2268.     PastUnit *pastunit;
  2269.     HistEvent *hevt;
  2270.  
  2271.     /* Write all the past units that might be mentioned in events.  These
  2272.        should already be sorted by id. */
  2273.     for (pastunit = past_unit_list; pastunit != NULL; pastunit = pastunit->next)
  2274.       write_past_unit(pastunit);
  2275.     newline_form();
  2276.     /* Now write all the events, doing the first one separately so as to
  2277.        simplify testing for the end of the history list (which is circular). */
  2278.     write_historical_event(history);
  2279.     for (hevt = history->next; hevt != history; hevt = hevt->next)
  2280.       write_historical_event(hevt);
  2281.     newline_form();
  2282. }
  2283.  
  2284. static void
  2285. write_past_unit(pastunit)
  2286. PastUnit *pastunit;
  2287. {
  2288.     start_form(key(K_EXU));
  2289.     add_num_to_form(pastunit->id);
  2290.     add_to_form(shortest_escaped_name(pastunit->type));
  2291.     add_num_to_form(pastunit->x);
  2292.     add_num_to_form(pastunit->y);
  2293.     add_num_to_form(side_number(pastunit->side));
  2294.     write_num_prop(key(K_Z), pastunit->z, 0, FALSE, FALSE);
  2295.     write_str_prop(key(K_N), pastunit->name, NULL, FALSE, FALSE);
  2296.     write_num_prop(key(K_NB), pastunit->number, 0, FALSE, FALSE);
  2297.     end_form();
  2298.     newline_form();
  2299. }
  2300.  
  2301. static void
  2302. write_historical_event(hevt)
  2303. HistEvent *hevt;
  2304. {
  2305.     int i;
  2306.     char *descs;
  2307.  
  2308.     /* Might be reasons not to write this event. */
  2309.     if (hevt->startdate < 0)
  2310.       return;
  2311.     start_form(key(K_EVT));
  2312.     add_num_to_form(hevt->startdate);
  2313.     add_to_form(hevtdefns[hevt->type].name);
  2314.     if (hevt->observers == ALLSIDES)
  2315.       add_to_form(key(K_ALL));
  2316.     else
  2317.       add_num_to_form(hevt->observers);
  2318.     descs = hevtdefns[hevt->type].datadescs;
  2319.     for (i = 0; descs[i] != '\0'; ++i) {
  2320.     switch (descs[i]) {
  2321.       case 'm':
  2322.       case 'n':
  2323.       case 's':
  2324.       case 'S':
  2325.       case 'u':
  2326.       case 'U':
  2327.       case 'x':
  2328.       case 'y':
  2329.         add_num_to_form(hevt->data[i]);
  2330.         break;
  2331.       default:
  2332.         run_warning("'%c' is not a recognized history data desc char", descs[i]);
  2333.         break;
  2334.     }
  2335.     }
  2336.     end_form();
  2337.     newline_form();
  2338. }
  2339.  
  2340. /* The comparison function for the image list just does "strcmp" order
  2341.    and *requires* that all image families be named and named uniquely. */
  2342.  
  2343. static void sort_all_recorded_images PARAMS ((void));
  2344.  
  2345. static int
  2346. image_name_compare(imf1, imf2)
  2347. #ifdef THINK_C
  2348. const
  2349. #endif
  2350. void *imf1, *imf2;
  2351. {
  2352.     return strcmp((*((ImageFamily **) imf1))->name,
  2353.           (*((ImageFamily **) imf2))->name);
  2354. }
  2355.  
  2356. static void
  2357. sort_all_recorded_images()
  2358. {
  2359.     qsort(&(recorded_imfs[0]), num_recorded_imfs, sizeof(ImageFamily *), image_name_compare);
  2360. }
  2361.  
  2362. static void
  2363. write_images()
  2364. {
  2365.     int i;
  2366.  
  2367.     if (recorded_imfs == NULL || num_recorded_imfs == 0)
  2368.       return;
  2369.     sort_all_recorded_images();
  2370.     for (i = 0; i < num_recorded_imfs; ++i) {
  2371.     write_imf(fp, recorded_imfs[i]);
  2372.     }
  2373. }
  2374.  
  2375. /* This is a generalized routine to do run-length-encoding of area layers.
  2376.    It uses hook fns to acquire data at a point and an optional translator to
  2377.    do any last-minute fixing.  It can use either a char or numeric encoding,
  2378.    depending on the expected range of values. */
  2379.  
  2380. static void
  2381. write_rle(datafn, lo, hi, translator, compress)
  2382. int (*datafn) PARAMS ((int, int)), lo, hi, (*translator) PARAMS ((int)), compress;
  2383. {
  2384.     int width, height, x, y, x0, y0, run, runval, val, trval;
  2385.     int numbad = 0;
  2386.  
  2387.     width = area.width;  height = area.height;
  2388.     if (doreshape) {
  2389.     width = reshaper->final_width;  height = reshaper->final_height;
  2390.     }
  2391.     for (y = height-1; y >= 0; --y) {
  2392.     space_form();
  2393.     space_form();
  2394.     fprintf(fp, "\"");
  2395.     run = 0;
  2396.     x0 = 0;  y0 = y;
  2397.     if (doreshape)
  2398.       original_point(0, y, &x0, &y0);
  2399.     val = (*datafn)(x0, y0);
  2400.     /* Zero out anything not in the world, unless reshaping. */
  2401.     if (!doreshape && !in_area(x0, y0))
  2402.       val = 0;
  2403.     /* Check that the data falls within bounds, clip if not. */
  2404.     if (lo <= hi && !between(lo, val, hi) && in_area(x0, y0)) {
  2405.         ++numbad;
  2406.         if (val < lo)
  2407.           val = lo;
  2408.         if (val > hi)
  2409.           val = hi;
  2410.     }
  2411.     runval = val;
  2412.     for (x = 0; x < width; ++x) {
  2413.         x0 = x;  y0 = y;
  2414.         if (doreshape)
  2415.           original_point(x, y, &x0, &y0);
  2416.         val = (*datafn)(x0, y0);
  2417.         /* Zero out anything not in the world, unless reshaping. */
  2418.         if (!doreshape && !in_area(x0, y0))
  2419.           val = 0;
  2420.         /* Check that the data falls within bounds, clip if not. */
  2421.         if (lo <= hi && !between(lo, val, hi) && in_area(x0, y0)) {
  2422.         ++numbad;
  2423.         if (val < lo)
  2424.           val = lo;
  2425.         if (val > hi)
  2426.           val = hi;
  2427.         }
  2428.         if (val == runval && compress) {
  2429.         run++;
  2430.         } else {
  2431.         trval = (translator != NULL ? (*translator)(runval) : runval);
  2432.         write_run(run, trval);
  2433.         /* Start a new run. */
  2434.         runval = val;
  2435.         run = 1;
  2436.         }
  2437.     }
  2438.     /* Finish off the row. */
  2439.     trval = (translator != NULL ? (*translator)(val) : val);
  2440.     write_run(run, trval);
  2441.     fprintf(fp, "\"");
  2442.     newline_form();
  2443.     }
  2444.     if (numbad > 0) {
  2445.     run_warning("%d values not between %d and %d", numbad, lo, hi);
  2446.     }
  2447. }
  2448.  
  2449. /* Write a single run, using the most compact encoding possible.
  2450.    0 - 29 is 'a' - '~', 30 - 63 is ':' - '[' */ 
  2451.  
  2452. static void
  2453. write_run(run, val)
  2454. int run, val;
  2455. {
  2456.     if (run > 1) {
  2457.     fprintf(fp, "%d", run);
  2458.     if (!between(0, val, 63))
  2459.       fprintf(fp, "*");
  2460.     }
  2461.     if (between(0, val, 29)) {
  2462.     fprintf(fp, "%c", val + 'a');
  2463.     } else if (between(30, val, 63)) {
  2464.     fprintf(fp, "%c", val - 30 + ':');
  2465.     } else {
  2466.     fprintf(fp, "%d,", val);
  2467.     }
  2468. }
  2469.  
  2470. /* Compute and return the corresponding point in an area being reshaped. */
  2471.  
  2472. static int
  2473. reshaped_point(x1, y1, x2p, y2p)
  2474. int x1, y1, *x2p, *y2p;
  2475. {
  2476.     *x2p = (((x1 - reshaper->subarea_x) * reshaper->final_subarea_width )
  2477.         / reshaper->subarea_width ) + reshaper->final_subarea_x;
  2478.     *y2p = (((y1 - reshaper->subarea_y) * reshaper->final_subarea_height)
  2479.         / reshaper->subarea_height) + reshaper->final_subarea_y;
  2480.     return TRUE;
  2481. }
  2482.  
  2483. static int
  2484. original_point(x1, y1, x2p, y2p)
  2485. int x1, y1, *x2p, *y2p;
  2486. {
  2487.     *x2p = (((x1 - reshaper->final_subarea_x) * reshaper->subarea_width )
  2488.         / reshaper->final_subarea_width ) + reshaper->subarea_x;
  2489.     *y2p = (((y1 - reshaper->final_subarea_y) * reshaper->subarea_height)
  2490.         / reshaper->final_subarea_height) + reshaper->subarea_y;
  2491.     return inside_area(*x2p, *y2p);
  2492. }
  2493.  
  2494.